<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha256-Z1K5uhUaJXA7Ll0XrZ/0JhX4lAtZFpT6jkKrEDT0drU=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"example.com","root":"/","images":"/images","scheme":"Muse","darkmode":false,"version":"8.14.1","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":-1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta property="og:type" content="website">
<meta property="og:title" content="JsyBlog">
<meta property="og:url" content="http://example.com/page/7/index.html">
<meta property="og:site_name" content="JsyBlog">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="SongyangJi">
<meta name="twitter:card" content="summary">


<link rel="canonical" href="http://example.com/page/7/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":true,"isPost":false,"lang":"zh-CN","comments":"","permalink":"","path":"page/7/index.html","title":""}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>JsyBlog</title>
  








  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <h1 class="site-title">JsyBlog</h1>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-overview-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">SongyangJi</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">251</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">45</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">109</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner index posts-expand">

    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2022/09/28/Linux%E7%BD%91%E7%BB%9C%E7%9B%91%E6%8E%A7/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2022/09/28/Linux%E7%BD%91%E7%BB%9C%E7%9B%91%E6%8E%A7/" class="post-title-link" itemprop="url">Linux网络监控</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>
      

      <time title="创建时间：2022-09-28 11:00:23 / 修改时间：12:29:43" itemprop="dateCreated datePublished" datetime="2022-09-28T11:00:23+08:00">2022-09-28</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Linux/" itemprop="url" rel="index"><span itemprop="name">Linux</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="netstat"><a href="#netstat" class="headerlink" title="netstat"></a>netstat</h1><p>在linux一般使用netstat 来查看系统端口使用情况步。     netstat命令是一个监控TCP&#x2F;IP网络的非常有用的工具，它可以显示路由表、实际的网络连接以及每一个网络接口设备的。</p>
<p><strong>netstat</strong>命令的功能是<strong>显示网络连接、路由表和网络接口信息</strong>，可以让用户得知目前都有<strong>哪些网络连接正在运作</strong>。 </p>
<p>该命令的一般格式为：   </p>
<p>netstat [选项]</p>
<p>命令中各选项的含义如下：  </p>
<p>-a 显示所有socket，包括正在监听的。</p>
<p>-c 每隔1秒就重新显示一遍，直到用户中断它。</p>
<p>-i 显示所有网络接口的信息，格式同“ifconfig -e”。</p>
<p>-n <strong>以网络IP地址代替名称</strong>，显示出网络连接情形。</p>
<p>-r 显示核心路由表，格式同“route -e”。</p>
<p>-t 显示TCP协议的连接情况。</p>
<p>-u 显示UDP协议的连接情况。</p>
<p>-v 显示正在进行的工作。</p>
<p>-p：显示 PID 和程序名；</p>
<h3 id="关键列解释"><a href="#关键列解释" class="headerlink" title="关键列解释:"></a><strong>关键列解释:</strong></h3><ul>
<li>Proto 表示协议类型</li>
<li>LocalAddress 表示本地地址</li>
<li>ForeignAddress 表示对端地址</li>
<li>State 表示状态(对于 TCP 有效, UDP 没有状态概念)</li>
<li>PID&#x2F;Program name 表示对应的进程id和进程名</li>
</ul>
<p>然后用筛选拿到想要的信息。</p>
<p>常用的组合：</p>
<ol>
<li><strong>查看进程名为firefox的连接</strong></li>
</ol>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -anp | grep firefox</span><br></pre></td></tr></table></figure>

<ol start="2">
<li><strong>查看111端口被那个进程调用</strong></li>
</ol>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -anp | grep 111</span><br></pre></td></tr></table></figure>

<ol start="3">
<li><strong>根据连接状态查询</strong></li>
</ol>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -an | grep LISTEN</span><br></pre></td></tr></table></figure>

<p>在这些状态中，我们最常用的就是 LISTEN 和 ESTABLISHED 状态，一种代表正在监听，另一种代表已经连接。</p>
<blockquote>
<p><a target="_blank" rel="noopener" href="https://www.oschina.net/translate/10-basic-linux-networking-and-monitoring?print">https://www.oschina.net/translate/10-basic-linux-networking-and-monitoring?print</a></p>
</blockquote>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2022/09/28/%E5%88%86%E5%B8%83%E5%BC%8FID/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2022/09/28/%E5%88%86%E5%B8%83%E5%BC%8FID/" class="post-title-link" itemprop="url">分布式ID</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2022-09-28 10:48:10" itemprop="dateCreated datePublished" datetime="2022-09-28T10:48:10+08:00">2022-09-28</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2022-10-09 01:16:03" itemprop="dateModified" datetime="2022-10-09T01:16:03+08:00">2022-10-09</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%88%86%E5%B8%83%E5%BC%8F/" itemprop="url" rel="index"><span itemprop="name">分布式</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="UUID"><a href="#UUID" class="headerlink" title="UUID"></a>UUID</h1><p><strong>优点：</strong></p>
<ul>
<li>生成足够简单，本地生成无网络消耗，具有唯一性</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>无序的字符串，不具备趋势自增特性</li>
<li>没有具体的业务含义</li>
<li>长度过长16 字节128位，36位长度的字符串，存储以及查询对MySQL的性能消耗较大，MySQL官方明确建议主键要尽量越短越好，作为数据库主键 <code>UUID</code> 的无序性会导致数据位置频繁变动，严重影响性能。</li>
</ul>
<h1 id="Snowflake——雪花算法"><a href="#Snowflake——雪花算法" class="headerlink" title="Snowflake——雪花算法"></a>Snowflake——雪花算法</h1><p>雪花算法（Snowflake）是twitter公司内部分布式项目采用的ID生成算法，开源后广受国内大厂的好评，在该算法影响下各大公司相继开发出各具特色的分布式生成器。</p>
<p><img src="https://pic2.zhimg.com/80/v2-4f51c7b6704323cc376b5a8a9a7cad09_1440w.jpg"></p>
<p><code>Snowflake</code>生成的是Long类型的ID，一个Long类型占8个字节，每个字节占8比特，也就是说一个Long类型占64个比特。</p>
<p>Snowflake ID组成结构：<code>正数位</code>（占1比特）+ <code>时间戳</code>（占41比特）+ <code>机器ID</code>（占5比特）+ <code>数据中心</code>（占5比特）+ <code>自增值</code>（占12比特），总共64比特组成的一个Long类型。</p>
<ul>
<li>第一个bit位（1bit）：Java中long的最高位是符号位代表正负，正数是0，负数是1，一般生成ID都为正数，所以默认为0。</li>
<li>时间戳部分（41bit）：毫秒级的时间，不建议存当前时间戳，而是用（当前时间戳 - 固定开始时间戳）的差值，可以使产生的ID从更小的值开始；41位的时间戳可以使用69年，(1L &lt;&lt; 41) &#x2F; (1000L * 60 * 60 * 24 * 365) &#x3D; 69年</li>
<li>工作机器id（10bit）：也被叫做<code>workId</code>，这个可以灵活配置，机房或者机器号组合都可以。</li>
<li>序列号部分（12bit），自增值支持同一毫秒内同一个节点可以生成4096个ID</li>
</ul>
<p>根据这个算法的逻辑，只需要将这个算法用Java语言实现出来，封装为一个工具方法，那么各个业务应用可以直接使用该工具方法来获取分布式ID，只需保证每个业务应用有自己的工作机器id即可，而不需要单独去搭建一个获取分布式ID的应用。</p>
<h2 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h2><p><strong>效率高</strong><br>生成id的效率比较快，最高在1ms内可以生成2的12次方，也就是4096个id。<br><strong>不依赖其他组件</strong><br>生成id的过程中，主要是根据时间戳，workID，序列号来进行生成，可以做到不额外依赖其他组件，只依赖于本地系统时间独立地生成id。</p>
<h2 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</h2><p><strong>易造成数据倾斜的问题</strong><br>举例：一个数据库中总共有10个id，分别是</p>
<p>0，25，26，27，28，29，30，31，32，100</p>
<p>id的最小值是0，最大值是100，按照id最大值减去最小值，进行范围切分，分成四段的话，范围是以下四个范围：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"> </span><br><span class="line">[``0``,``25``), 存在``1``个id，值分别是``0` `[``25``,``50``) 存在``8``个id，值分别是``25``，``26``，``27``，``28``，``29``，``30``，``31``，``32` `[``50``,``75``),存在``0``个id [``75``,``100``] 存在``1``个``100``，值是``100</span><br></pre></td></tr></table></figure>

<p>这样明显就会存在数据倾斜的问题，就是[25,50) 这个区间存在的id数量特别多，而其他区间存在的id数量特别少。如果我们用Sqoop将MySQL中的数据导入到Hive中去时，就是按照这种id最大值减去最小值，进行范围切分实现方法进行数据分片，然后多线程进行数据导入，每个线程负责一个分片的数据，数据不均匀的话，导入的时间就会变长，有些线程分配的数据量少，导入很快，有些线程分配的数据量大导入很慢。总导入时间取决于最慢的那个线程的时间。</p>
<p>使用Snowflake生成的id，id值的大小因为取决于生成id时的时间戳，如果某一个时间段爬取了大量文章进行入库，在很短的时候内生成了很多id，而其他时间段生成id数量很少，在使用Sqoop导入数据时就会有数据倾斜的问题，需要单独自己进行数据切分，让数据变均匀，然后进行导入。</p>
<h1 id="号段模式"><a href="#号段模式" class="headerlink" title="号段模式"></a>号段模式</h1><p>号段模式是当下分布式ID生成器的主流实现方式之一，号段模式可以理解为<strong>从数据库批量的获取自增ID</strong>，每次从数据库取出一个号段范围，例如 [0,1000) 代表1000个ID，具体的业务服务将本号段，生成1~1000的自增ID并加载到内存。</p>
<p>表结构如下：</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> id_generator (</span><br><span class="line">  id <span class="type">int</span>(<span class="number">10</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  max_id <span class="type">bigint</span>(<span class="number">20</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;当前最大id&#x27;</span>,</span><br><span class="line">  step <span class="type">int</span>(<span class="number">20</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;号段的布长&#x27;</span>,</span><br><span class="line">  biz_type	<span class="type">int</span>(<span class="number">20</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;业务类型&#x27;</span>,</span><br><span class="line">  version <span class="type">int</span>(<span class="number">20</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;版本号&#x27;</span>,</span><br><span class="line">  <span class="keyword">PRIMARY</span> KEY (`id`)</span><br><span class="line">) </span><br></pre></td></tr></table></figure>



<p>eg.<br><img src="https://pic3.zhimg.com/80/v2-abc2633c6ff85daf95fca018f717a24e_1440w.png"></p>
<ul>
<li><p>biz_type ：代表不同业务类型；</p>
</li>
<li><p>max_id ：当前最大的可用id；</p>
</li>
<li><p>step ：代表号段的长度；</p>
</li>
<li><p>version ：是一个乐观锁，每次都更新version，保证并发时数据的正确性。</p>
</li>
</ul>
<p>等这批号段ID用完，再次向数据库申请新号段，对<code>max_id</code>字段做一次<code>update</code>操作，<code>update max_id= max_id + step</code>，update成功则说明新号段获取成功，新的号段范围是<code>(max_id ,max_id +step]</code>。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">update</span> id_generator <span class="keyword">set</span> max_id <span class="operator">=</span> #&#123;max_id<span class="operator">+</span>step&#125;, version <span class="operator">=</span> version <span class="operator">+</span> <span class="number">1</span> <span class="keyword">where</span> version <span class="operator">=</span> # &#123;version&#125; <span class="keyword">and</span> biz_type <span class="operator">=</span> XXX</span><br></pre></td></tr></table></figure>





<p>由于多业务端可能同时操作，所以采用版本号<code>version</code>乐观锁方式更新，这种<code>分布式ID</code>生成方式不强依赖于数据库，不会频繁的访问数据库，对数据库的压力小很多。</p>
<h2 id="优点-1"><a href="#优点-1" class="headerlink" title="优点"></a>优点</h2><p><strong>效率高</strong><br>生成id的效率取决于step的大小，不会像主键自增生成id那样再受限于数据库的数量。</p>
<h2 id="缺点-1"><a href="#缺点-1" class="headerlink" title="缺点"></a>缺点</h2><p><strong>强依赖于数据库</strong><br>还是强依赖于数据库，数据库宕机后，虽然id生成系统靠内存中还未使用完id，可以维持系统正常运行一段时间，但是数据库不可用还是会导致整个系统不可用。</p>
<p><strong>id是连续的</strong><br>容易造成被爬取，以及被竞争对手猜测出一天的订单量。</p>
<h1 id="美团（Leaf）"><a href="#美团（Leaf）" class="headerlink" title="美团（Leaf）"></a>美团（Leaf）</h1><p>Leaf同时支持号段模式和snowflake算法模式，可以切换使用。</p>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2022/09/27/%E9%98%B2%E9%87%8D%E4%B8%8E%E5%B9%82%E7%AD%89/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2022/09/27/%E9%98%B2%E9%87%8D%E4%B8%8E%E5%B9%82%E7%AD%89/" class="post-title-link" itemprop="url">防重与幂等</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2022-09-27 22:39:04" itemprop="dateCreated datePublished" datetime="2022-09-27T22:39:04+08:00">2022-09-27</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2022-09-28 13:38:19" itemprop="dateModified" datetime="2022-09-28T13:38:19+08:00">2022-09-28</time>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          
      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2022/09/27/MySQL%E6%85%A2%E6%9F%A5%E8%AF%A2%E4%BC%98%E5%8C%96/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2022/09/27/MySQL%E6%85%A2%E6%9F%A5%E8%AF%A2%E4%BC%98%E5%8C%96/" class="post-title-link" itemprop="url">MySQL慢查询优化</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2022-09-27 22:10:48" itemprop="dateCreated datePublished" datetime="2022-09-27T22:10:48+08:00">2022-09-27</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2022-10-09 09:39:59" itemprop="dateModified" datetime="2022-10-09T09:39:59+08:00">2022-10-09</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/MySQL/" itemprop="url" rel="index"><span itemprop="name">MySQL</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="1-发现-监控慢查询"><a href="#1-发现-监控慢查询" class="headerlink" title="1. 发现+监控慢查询"></a>1. 发现+监控慢查询</h1><h2 id="Mysql提供的慢查询日志"><a href="#Mysql提供的慢查询日志" class="headerlink" title="Mysql提供的慢查询日志"></a>Mysql提供的慢查询日志</h2><p><strong>MySQL的慢查询，全名是慢查询日志，是MySQL提供的一种日志记录，用来记录在MySQL中响应时间超过阀值的语句。</strong></p>
<p><strong>相关参数</strong></p>
<ol>
<li>slow_query_log : 是否开启慢查询日志</li>
<li>slow_query_log_file : 慢查询日志文件名及路径</li>
<li>long_query_time : 指定慢查询时间阈(yu)值，sql执行时间大于该阈值（不包括该值本身，如在sql执行中花费的时间等于，下面的2秒时，不会被记录）将被记录下来,生产环境中1~2秒范围均可</li>
<li>log_queries_not_using_indexes : 将没有使用索引的语句记录至慢查询日志中，</li>
<li>log_throttle_queries_not_using_indexes : 限制每分钟内，在慢查询日志中，去记录没有使用索引的SQL语句的次数,因为没有使用索引的SQL可能会短时间重复执行，为了避免日志快速增大，限制每分钟的记录次数</li>
<li>min_examined_row_limit : 扫描全表少于该值的记录将不会被记录至慢查询日志,结合去记录没有使用索引的SQL语句的例子，有可能存在某一个表，数据量维持在百行左右，且没有建立索引。这种表即使不建立索引，查询也很快，扫描记录很小，如果确定有这种表，则可以通过此参数设置，将这个SQL不记录到慢查询日志。</li>
</ol>
<p><strong>开启方式</strong></p>
<ol>
<li>修改配置文件</li>
<li>MySQL shell</li>
</ol>
<p><img src="https://pic3.zhimg.com/80/v2-b2bd80889ea54240a64ec1510c73a13a_1440w.png"></p>
<h2 id="MyBatis-plus的性能分析插件"><a href="#MyBatis-plus的性能分析插件" class="headerlink" title="MyBatis -plus的性能分析插件"></a>MyBatis -plus的性能分析插件</h2><blockquote>
<p>性能分析拦截器，用于输出每条 SQL 语句及其执行时间</p>
</blockquote>
<p><a target="_blank" rel="noopener" href="https://hfbbob1.gitbooks.io/mybatis-plus/content/xing-neng-fen-xi-cha-jian.html">https://hfbbob1.gitbooks.io/mybatis-plus/content/xing-neng-fen-xi-cha-jian.html</a></p>
<h1 id="2-分析慢查询日志——explain"><a href="#2-分析慢查询日志——explain" class="headerlink" title="2. 分析慢查询日志——explain"></a>2. 分析慢查询日志——explain</h1><p>直接分析mysql慢查询日志 ,利用explain关键字可以模拟优化器执行SQL查询语句，来分析sql慢查询语句。</p>
<p>Explain是一个非常有的命令，可以用来获取关于查询执行计划的信息，以及如何解释输出。Explain命令是查看查询优化器如何决定执行查询的主要方法。这个功能有一定的局限性，并不总是会说出真相，但是它的输出是可以获取的最好信息，值得花时间了解，可以学习到查询是如何执行的。</p>
<p>explain的输出列：<br><img src="https://img-blog.csdn.net/20170509232741017?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3VzZXl1a3Vp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast"></p>
<p><strong>其中最重要的字段为：id、type、key、rows、Extra</strong></p>
<ol>
<li><strong>id列</strong></li>
</ol>
<p>这一列总是包含一个编号，标示select所属的行。</p>
<p><strong>数字越大越先执行，如果说数字一样大，那么就从上往下依次执行</strong>，id列为null的就表示这是一个结果集，不需要使用它来进行查询。</p>
<ol start="2">
<li><strong>select_type列</strong></li>
</ol>
<p>这一列显示了对应行是简单还是复杂select。</p>
<p>常见的有：</p>
<p>A：simple：表示不包含union操作或者不包含子查询的简单select查询。有连接查询时，外层的查询为simple，且只有一个</p>
<p>B：primary：一个需要union操作或者含有子查询的select，位于最外层的单位查询的select_type即为primary。且只有一个</p>
<p>C：union：union连接的两个select查询，第一个查询是dervied派生表，除了第一个表外，第二个以后的表select_type都是union</p>
<p>D：dependent union：与union一样，出现在union 或union all语句中，但是这个查询要受到外部查询的影响</p>
<p>E：union result：包含union的结果集，在union和union all语句中,因为它不需要参与查询，所以id字段为null</p>
<p>F：subquery：除了from字句中包含的子查询外，其他地方出现的子查询都可能是subquery</p>
<p>G：dependent subquery：与dependentunion类似，表示这个subquery的查询要受到外部表查询的影响</p>
<p>H：derived：from字句中出现的子查询，也叫做派生表，其他数据库中可能叫做内联视图或嵌套select</p>
<ol start="3">
<li>table列</li>
</ol>
<p>这一列显示了对应行正在访问查询的表名，如果查询使用了别名，那么这里显示的是别名，如果不涉及对数据表的操作，那么这显示为null，如果显示为尖括号括起来的<derived N>就表示这个是临时表，后边的N就是执行计划中的id，表示结果来自于这个查询产生。如果是尖括号括起来的&lt;union M,N&gt;，与<derived N>类似，也是一个临时表，表示这个结果来自于union查询的id为M,N的结果集。</p>
<ol start="4">
<li><strong>type列</strong></li>
</ol>
<p>这一列显示了<strong>访问类型，即MySQL决定如何查找表中的行</strong>。</p>
<p><strong>依次从好到差：system，const，eq_ref，ref，fulltext，ref_or_null，unique_subquery，index_subquery，range，index_merge，index，ALL，除了all之外，其他的type都可以使用到索引，除了index_merge之外，其他的type只可以用到一个索引</strong></p>
<p>A：system：表中只有一行数据或者是空表，且只能用于myisam和memory表。如果是Innodb引擎表，type列在这个情况通常都是all或者index</p>
<p>B：<strong>const：使用唯一索引或者主键</strong>，返回记录一定是1行记录的等值where条件时，通常type是const。其他数据库也叫做唯一索引扫描</p>
<p>C：<strong>eq_ref</strong>：出现在要连接过个表的查询计划中，<strong>驱动表只返回一行数据，且这行数据是第二个表的主键或者唯一索引</strong>，且必须为not null，唯一索引和主键是多列时，只有所有的列都用作比较时才会出现eq_ref</p>
<p>D：<strong>ref</strong>：不像eq_ref那样要求连接顺序，也没有主键和唯一索引的要求，只要使用相等条件检索时就可能出现，常见与辅助索引的等值查找。或者多列主键、唯一索引中，使用第一个列之外的列作为等值查找也会出现，总之，返回数据不唯一的等值查找就可能出现。</p>
<p>E：fulltext：全文索引检索，要注意，全文索引的优先级很高，若全文索引和普通索引同时存在时，mysql不管代价，优先选择使用全文索引</p>
<p>F：ref_or_null：与ref方法类似，只是增加了null值的比较。实际用的不多。</p>
<p>G：unique_subquery：用于where中的in形式子查询，子查询返回不重复值唯一值</p>
<p>H：index_subquery：用于in形式子查询使用到了辅助索引或者in常数列表，子查询可能返回重复值，可以使用索引将子查询去重。</p>
<p>I：<strong>range：索引范围扫描</strong>，常见于使用&gt;,&lt;,isnull,between ,in ,like等运算符的查询中。</p>
<p>J：index_merge：表示查询使用了两个以上的索引，最后取交集或者并集，常见and ，or的条件使用了不同的索引，官方排序这个在ref_or_null之后，但是实际上由于要读取所个索引，性能可能大部分时间都不如range</p>
<p>K：<strong>index：索引全表扫描</strong>，<strong>把索引从头到尾扫一遍</strong>，常见于使用索引列就可以处理不需要读取数据文件的查询、可以使用索引排序或者分组的查询。</p>
<p>L：<strong>all：全表扫描数据文件</strong>，然后再在server层进行过滤返回符合要求的记录。</p>
<ol start="5">
<li><strong>possible_keys列</strong></li>
</ol>
<p><strong>查询可能使用到的索引</strong>都会在这里列出来。这个列表是优化过程早期创建的，因此有些罗列出来的索引有可能后续是没用的。</p>
<ol start="6">
<li><strong>key列</strong></li>
</ol>
<p>显示了<strong>查询真正使用到的索引</strong>，select_type为index_merge时，这里可能出现两个以上的索引，其他的select_type这里只会出现一个。</p>
<p>如果该索引没有出现在possible_keys列中，那么MySQL选用它是出于另外的原因，比如选择了一个覆盖索引。</p>
<p>possible_keys揭示了哪一个索引能有助于高效地进行查找，key显示了优化采用哪一个索引可以最小化查询成本。</p>
<ol start="7">
<li>key_len列</li>
</ol>
<p>用于处理查询的索引长度，如果是单列索引，那就整个索引长度算进去，如果是多列索引，那么查询不一定都能使用到所有的列，具体使用到了多少个列的索引，这里就会计算进去，没有使用到的列，这里不会计算进去。留意下这个列的值，算一下你的多列索引总长度就知道有没有使用到所有的列了。要注意，mysql的ICP特性使用到的索引不会计入其中。另外，key_len只计算where条件用到的索引长度，而排序和分组就算用到了索引，也不会计算到key_len中。</p>
<ol start="8">
<li>ref列</li>
</ol>
<p>如果是使用的常数等值查询，这里会显示const，如果是连接查询，被驱动表的执行计划这里会显示驱动表的关联字段，如果是条件使用了表达式或者函数，或者条件列发生了内部隐式转换，这里可能显示为func</p>
<ol start="9">
<li><strong>rows列</strong></li>
</ol>
<p>这里是执<strong>行计划中估算的扫描行数</strong>，不是精确值。</p>
<ol start="10">
<li><strong>extra列</strong></li>
</ol>
<p>这个列可以显示的信息非常多，有几十种，常用的有</p>
<p>A：distinct：在select部分使用了distinc关键字</p>
<p>B：no tables used：不带from字句的查询或者Fromdual查询</p>
<p>C：使用not in()形式子查询或notexists运算符的连接查询，这种叫做反连接。即，一般连接查询是先查询内表，再查询外表，反连接就是先查询外表，再查询内表。</p>
<p>D：<strong>using filesort</strong>：排序时无法使用到索引时，就会出现这个。<strong>常见于order by和group by语句中</strong></p>
<p>E：<strong>using index：查询时不需要回表查询，直接通过索引就可以获取查询的数据。(覆盖索引)</strong></p>
<p>F：<strong>using join buffer</strong>（block nestedloop），using join buffer（batched key accss）：5.6.x之后的版本优化关联查询的BNL，BKA特性。主要是减少内表的循环数量以及比较顺序地扫描查询。</p>
<p>G：using sort_union，using_union，usingintersect，using sort_intersection：</p>
<p>using intersect：表示使用and的各个索引的条件时，该信息表示是从处理结果获取交集</p>
<p>using union：表示使用or连接各个使用索引的条件时，该信息表示从处理结果获取并集</p>
<p>using sort_union和usingsort_intersection：与前面两个对应的类似，只是他们是出现在用and和or查询信息量大时，先查询主键，然后进行排序合并后，才能读取记录并返回。</p>
<p>H：using temporary：表示使用了临时表存储中间结果。临时表可以是内存临时表和磁盘临时表，执行计划中看不出来，需要查看status变量，used_tmp_table，used_tmp_disk_table才能看出来。</p>
<p>I：<strong>using where</strong>：<strong>表示存储引擎返回的记录并不是所有的都满足查询条件，需要在server层进行过滤。</strong>查询条件中分为限制条件和检查条件，5.6之前，存储引擎只能根据限制条件扫描数据并返回，然后server层根据检查条件进行过滤再返回真正符合查询的数据。5.6.x之后支持ICP特性，可以把检查条件也下推到存储引擎层，不符合检查条件和限制条件的数据，直接不读取，这样就大大减少了存储引擎扫描的记录数量。extra列显示using index condition</p>
<p>J：firstmatch(tb_name)：5.6.x开始引入的优化子查询的新特性之一，常见于where字句含有in()类型的子查询。如果内表的数据量比较大，就可能出现这个</p>
<p>K：loosescan(m..n)：5.6.x之后引入的优化子查询的新特性之一，在in()类型的子查询中，子查询返回的可能有重复记录时，就可能出现这个</p>
<p>除了这些之外，还有很多查询数据字典库，执行计划过程中就发现不可能存在结果的一些提示信息</p>
<ol start="11">
<li>filtered列</li>
</ol>
<p>使用explain extended时会出现这个列，5.7之后的版本默认就有这个字段，不需要使用explain extended了。这个字段表示存储引擎返回的数据在server层过滤后，剩下多少满足查询的记录数量的比例，注意是百分比，不是具体记录数。</p>
<h1 id="3-常见的慢查询优化"><a href="#3-常见的慢查询优化" class="headerlink" title="3. 常见的慢查询优化"></a>3. 常见的慢查询优化</h1><h2 id="索引相关"><a href="#索引相关" class="headerlink" title="索引相关"></a>索引相关</h2><h3 id="索引没起作用的情况"><a href="#索引没起作用的情况" class="headerlink" title="索引没起作用的情况"></a>索引没起作用的情况</h3><ol>
<li>使用LIKE关键字的查询语句</li>
<li>范围查询破坏最左前缀匹配原则</li>
<li>索引字段参与计算</li>
</ol>
<h3 id="建索引的几大原则"><a href="#建索引的几大原则" class="headerlink" title="建索引的几大原则"></a>建索引的几大原则</h3><p>1.<strong>最左前缀匹配原则</strong>，非常重要的原则，mysql会一直向右匹配直到遇到范围查询(&gt;、&lt;、between、like)就停止匹配，比如a &#x3D; 1 and b &#x3D; 2 and c &gt; 3 and d &#x3D; 4 如果建立(a,b,c,d)顺序的索引，d是用不到索引的，如果建立(a,b,d,c)的索引则都可以用到，a,b,d的顺序可以任意调整。</p>
<p>2.&#x3D;和in可以乱序，比如a &#x3D; 1 and b &#x3D; 2 and c &#x3D; 3 建立(a,b,c)索引可以任意顺序，mysql的查询优化器会帮你优化成索引可以识别的形式。</p>
<p>3.<strong>尽量选择区分度高的列作为索引</strong>，区分度的公式是count(distinct col)&#x2F;count(*)，表示字段不重复的比例，比例越大我们扫描的记录数越少，唯一键的区分度是1，而一些状态、性别字段可能在大数据面前区分度就是0，那可能有人会问，这个比例有什么经验值吗？使用场景不同，这个值也很难确定，一般需要join的字段我们都要求是0.1以上，即平均1条扫描10条记录。</p>
<p>4.<strong>索引列不能参与计算</strong>，保持列“干净”，比如from_unixtime(create_time) &#x3D; ’2014-05-29’就不能使用到索引，原因很简单，b+树中存的都是数据表中的字段值，但进行检索时，需要把所有元素都应用函数才能比较，显然成本太大。所以语句应该写成create_time &#x3D; unix_timestamp(’2014-05-29’)。</p>
<p>5.<strong>尽量复用已有的索引</strong>，不要新建索引。比如表中已经有a的索引，现在要加(a,b)的索引，那么只需要修改原来的索引即可。</p>
<h2 id="优化数据库结构"><a href="#优化数据库结构" class="headerlink" title="优化数据库结构"></a>优化数据库结构</h2><p><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/137368446">分库分表相关</a></p>
<p>（这里介绍一点最简单的）</p>
<ul>
<li>将字段很多的表分解成多个表</li>
</ul>
<p>对于字段比较多的表，如果有些字段的使用频率很低，可以将这些字段分离出来形成新表。因为当一个表的数据量很大时，会由于使用频率低的字段的存在而变慢。</p>
<ul>
<li>增加中间表（但是破坏了数据库范式）</li>
</ul>
<p>对于需要经常联合查询的表，可以建立中间表以提高查询效率。通过建立中间表，把需要经常联合查询的数据插入到中间表中，然后将原来的联合查询改为对中间表的查询，以此来提高查询效率。</p>
<h2 id="分页相关"><a href="#分页相关" class="headerlink" title="分页相关"></a>分页相关</h2><p>在系统中需要分页的操作通常会使用limit加上偏移量的方法实现，同时加上合适的order by 子句。如果有对应的索引，通常效率会不错，否则MySQL需要做大量的<strong>文件排序</strong>操作。</p>
<p>一个非常令人头疼问题就是当偏移量非常大的时候，</p>
<p>例如可能是limit 10000,20这样的查询，这是mysql需要查询10020条然后只返回最后20条，前面的10000条记录都将被舍弃，这样的代价很高。</p>
<p>优化此类查询的一个最简单的方法是尽可能的使用<strong>索引覆盖扫描</strong>，而不是查询所有的列。然后根据需要做一次关联操作再返回所需的列。对于偏移量很大的时候这样做的效率会得到很大提升。</p>
<p>对于下面的查询：<br>select id,title from collect limit 90000,10;<br>该语句存在的最大问题在于limit M,N中偏移量M太大（我们暂不考虑筛选字段上要不要添加索引的影响），导致每次查询都要先从整个表中找到满足条件 的前M条记录，之后舍弃这M条记录并从第M+1条记录开始再依次找到N条满足条件的记录。</p>
<p>如果表非常大，且筛选字段没有合适的索引，且M特别大那么这样的代价是非常高的。</p>
<p> 试想，<strong>如果我们下一次的查询能从前一次查询结束后标记的位置开始查找，找到满足条件的100条记录，并记下下一次查询应该开始的位置，以便于下一次查询能直接从该位置开始，这样就不必每次查询都先从整个表中先找到满足条件的前M条记录</strong>，舍弃，在从M+1开始再找到100条满足条件的记录了。</p>
<p>方法一：<strong>先查询出主键id值（或者直接带上id）</strong><br>select id,title from collect where id&gt;&#x3D;(select id from collect order by id limit 90000,1) limit 10;<br>原理：先查询出90000条数据对应的主键id的值，然后直接通过该id的值直接查询该id后面的数据。</p>
<p>方法二：<strong>关延迟联</strong><br>如果这个表非常大，那么这个查询可以改写成如下的方式：<br>select news.id, news.description from news inner join (select id from news order by title limit 50000,5) as myNew using(id);<br>这里的“关延迟联”将大大提升查询的效率，它让MySQL扫描尽可能少的页面，获取需要的记录后再根据关联列回原表查询需要的所有列。这个技术也可以用在优化关联查询中的limit。</p>
<h2 id="其他小trick"><a href="#其他小trick" class="headerlink" title="其他小trick"></a>其他小trick</h2><ul>
<li><strong>小表驱动大表</strong></li>
</ul>
<p>。。。。。。</p>
<blockquote>
<p>参考文章<a target="_blank" rel="noopener" href="https://tech.meituan.com/2014/06/30/mysql-index.html">https://tech.meituan.com/2014/06/30/mysql-index.html</a></p>
</blockquote>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2022/09/26/Zookeeper/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2022/09/26/Zookeeper/" class="post-title-link" itemprop="url">Zookeeper</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>
      

      <time title="创建时间：2022-09-26 11:01:58 / 修改时间：11:22:12" itemprop="dateCreated datePublished" datetime="2022-09-26T11:01:58+08:00">2022-09-26</time>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="节点类型"><a href="#节点类型" class="headerlink" title="节点类型"></a>节点类型</h1><p>1.持久节点(PERSISTENT)<br>持久节点，创建后一直存在，直到主动删除此节点。</p>
<p>2.持久顺序节点(PERSISTENT_SEQUENTIAL)<br>持久顺序节点，创建后一直存在，直到主动删除此节点。在ZK中，每个父节点会为它的第一级子节点维护一份时序，记录每个子节点创建的先后顺序。</p>
<p>3.临时节点(EPHEMERAL)<br>临时节点在客户端会话失效后节点自动清除。临时节点下面不能创建子节点。</p>
<p>4.临时顺序节点(EPHEMERAL_SEQUENTIAL)<br>临时节点在客户端会话失效后节点自动清除。临时节点下面不能创建子节点。父节点getChildren会获得顺序的节点列表。</p>
<h1 id="有哪几种角色"><a href="#有哪几种角色" class="headerlink" title="有哪几种角色"></a>有哪几种角色</h1><ol>
<li>Leader</li>
</ol>
<p>（1）事务请求的唯一调度和处理者，保证集群事务处理的顺序性</p>
<p>（2）集群内部各服务的调度者</p>
<ol start="2">
<li>Follower</li>
</ol>
<p>（1）处理客户端的非事务请求，转发事务请求给 Leader 服务器</p>
<p>（2）参与事务请求 Proposal 的投票</p>
<p>（3）参与 Leader 选举投票</p>
<ol start="3">
<li>Observer</li>
</ol>
<p>3.3.0 版本以后引入的一个服务器角色，在不影响集群事务处理能力的基础上提升集群的非事务处理能力</p>
<p>（1）处理客户端的非事务请求，转发事务请求给 Leader 服务器</p>
<p>（2）不参与任何形式的投票</p>
<h1 id="使用案例"><a href="#使用案例" class="headerlink" title="使用案例"></a>使用案例</h1><ul>
<li>服务注册与订阅（共用节点）</li>
<li>分布式通知（监听znode）</li>
<li>服务命名（znode特性）</li>
<li>数据订阅、发布（watcher）</li>
<li>分布式锁（临时节点）</li>
</ul>
<h2 id="分布式屏障（通知）"><a href="#分布式屏障（通知）" class="headerlink" title="分布式屏障（通知）"></a>分布式屏障（通知）</h2><p>分布式系统使用<em>障碍</em>来阻止对一组节点的处理，直到满足一个条件，此时所有节点都被允许继续进行。在 ZooKeeper 中通过指定一个屏障节点来实现屏障。如果屏障节点存在，则屏障就位。这是伪代码：</p>
<ol>
<li>客户端在屏障节点上调用 ZooKeeper API 的<strong>exists()函数，并将</strong><em>watch</em>设置为 true。</li>
<li>如果**exists()**返回 false，则障碍消失，客户端继续</li>
<li>否则，如果**exists()**返回 true，则客户端等待 ZooKeeper 为屏障节点发送监视事件。</li>
<li>当 watch 事件被触发时，客户端重新发出**exists()**调用，再次等待直到屏障节点被移除。</li>
</ol>
<h2 id="分布式锁"><a href="#分布式锁" class="headerlink" title="分布式锁"></a>分布式锁</h2><p>全局同步的完全分布式锁，这意味着在任何时间快照中，没有两个客户端认为他们持有相同的锁。这些可以使用 ZooKeeper 来实现。与优先级队列一样，首先定义一个锁节点。</p>
<blockquote>
<p>ZooKeeper recipes 目录中现在存在一个 Lock 实现。这与发布工件的发布 - zookeeper-recipes&#x2F;zookeeper-recipes-lock 目录一起分发。</p>
</blockquote>
<p>希望获得锁的客户端执行以下操作：</p>
<ol>
<li>使用路径名为“ <em>locknode</em> &#x2F;guid-lock-”并设置<em>序列</em>和<em>临时</em>标志调用<strong>create() 。</strong>如果缺少 create() 结果，则需要该<em>guid 。</em>请参阅下面的注释。</li>
<li><em>在不</em>设置监视标志的情况下在锁定节点上调用**getChildren()**（这对于避免羊群效应很重要）。</li>
<li>如果在步骤<strong>1</strong>中创建的路径名具有最小的序列号后缀，则客户端具有锁定并且客户端退出协议。</li>
<li>客户端调用**exists( )**并在锁定目录中的路径上设置了监视标志，并具有下一个最低序列号。</li>
<li>如果<strong>exists( )<strong>返回null，则转到步骤</strong>2</strong>。否则，请等待上一步的路径名通知，然后再转到第<strong>2</strong>步。</li>
</ol>
<p>解锁协议非常简单：希望释放锁的客户端只需删除他们在步骤 1 中创建的节点。</p>
<p>这里有几点需要注意：</p>
<ul>
<li>删除一个节点只会导致一个客户端唤醒，因为每个节点都被一个客户端监视。通过这种方式，您可以避免羊群效应。</li>
<li>没有轮询或超时。</li>
<li>由于您实现锁定的方式，很容易看到锁定争用、中断锁定、调试锁定问题等的数量。</li>
</ul>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2022/09/26/CountDownLatch%E3%80%81CyclicBarrier%E3%80%81Semaphore/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2022/09/26/CountDownLatch%E3%80%81CyclicBarrier%E3%80%81Semaphore/" class="post-title-link" itemprop="url">CountDownLatch、CyclicBarrier、Semaphore</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>
      

      <time title="创建时间：2022-09-26 03:53:22 / 修改时间：11:37:00" itemprop="dateCreated datePublished" datetime="2022-09-26T03:53:22+08:00">2022-09-26</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/JUC/" itemprop="url" rel="index"><span itemprop="name">JUC</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="CountDownLatch"><a href="#CountDownLatch" class="headerlink" title="CountDownLatch"></a>CountDownLatch</h1><p><strong>发令枪</strong>（通知后，一组线程才开始工作）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">CountDownLatch</span> <span class="variable">cdl</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CountDownLatch</span>(<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) &#123;</span><br><span class="line">            <span class="type">int</span> <span class="variable">x</span> <span class="operator">=</span> i;</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    cdl.await();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(<span class="string">&quot;end &quot;</span> + x);</span><br><span class="line">            &#125;).start();</span><br><span class="line">        &#125;</span><br><span class="line">        Thread.sleep(<span class="number">3000</span>);</span><br><span class="line">        cdl.countDown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p><strong>屏障</strong>（一组线程完成后，主线程工作）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">N</span> <span class="operator">=</span> <span class="number">5</span>;</span><br><span class="line">        <span class="type">CountDownLatch</span> <span class="variable">cdl</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CountDownLatch</span>(N);</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; N; i++) &#123;</span><br><span class="line">            <span class="type">int</span> <span class="variable">x</span> <span class="operator">=</span> i;</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    Thread.sleep(<span class="number">2000</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">                System.out.println(<span class="string">&quot;end &quot;</span> + x);</span><br><span class="line">                cdl.countDown();</span><br><span class="line">            &#125;).start();</span><br><span class="line">        &#125;</span><br><span class="line">        cdl.await();</span><br><span class="line">        System.out.println(<span class="string">&quot;end main&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h1 id="CyclicBarrier"><a href="#CyclicBarrier" class="headerlink" title="CyclicBarrier"></a>CyclicBarrier</h1><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure>





<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>CountDownLatch: 一个线程(或者多个)， 等待另外N个线程完成某个事情之后才能执行。</p>
<p>CyclicBarrier: N个线程相互等待，任何一个线程完成之前，所有的线程都必须等待。</p>
<p>这样应该就清楚一点了，对于CountDownLatch来说，重点是那个“一个线程”, 是它在等待， 而另外那N的线程在把“某个事情”做完之后可以继续等待，可以终止。而对于CyclicBarrier来说，重点是那N个线程，他们之间任何一个没有完成，所有的线程都必须等待。</p>
<p><a target="_blank" rel="noopener" href="https://cloud.tencent.com/developer/article/1648906">CycliBarriar和CountdownLatch有什么区别</a></p>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2022/09/26/%E7%94%9F%E4%BA%A7%E8%80%85%E3%80%81%E6%B6%88%E8%B4%B9%E8%80%85%E6%A8%A1%E5%BC%8F/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2022/09/26/%E7%94%9F%E4%BA%A7%E8%80%85%E3%80%81%E6%B6%88%E8%B4%B9%E8%80%85%E6%A8%A1%E5%BC%8F/" class="post-title-link" itemprop="url">生产者、消费者模式</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2022-09-26 02:51:27" itemprop="dateCreated datePublished" datetime="2022-09-26T02:51:27+08:00">2022-09-26</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2022-09-28 09:59:23" itemprop="dateModified" datetime="2022-09-28T09:59:23+08:00">2022-09-28</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" itemprop="url" rel="index"><span itemprop="name">设计模式</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="使用-Semaphore和循环数组"><a href="#使用-Semaphore和循环数组" class="headerlink" title="使用 Semaphore和循环数组"></a>使用 Semaphore和循环数组</h1><ul>
<li><strong>使用信号量限制对有限资源的访问</strong></li>
<li><strong>使用二进制信号量实现锁</strong><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.Semaphore;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: Song yang Ji</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@ProjectName</span>: learn-multiThread</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span>:</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ProducerThread</span> <span class="keyword">extends</span> <span class="title class_">Thread</span> &#123;</span><br><span class="line">    <span class="type">int</span> rate;</span><br><span class="line">    MultiProducerConsumer multiProducerConsumer;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ProducerThread</span><span class="params">(<span class="type">int</span> rate, MultiProducerConsumer multiProducerConsumer)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.multiProducerConsumer = multiProducerConsumer;</span><br><span class="line">        <span class="built_in">this</span>.rate = rate;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">run</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                multiProducerConsumer.produce();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(rate);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ConsumerThread</span> <span class="keyword">extends</span> <span class="title class_">Thread</span> &#123;</span><br><span class="line">    <span class="type">int</span> rate;</span><br><span class="line">    MultiProducerConsumer multiProducerConsumer;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ConsumerThread</span><span class="params">(<span class="type">int</span> rate,MultiProducerConsumer multiProducerConsumer)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.rate = rate;</span><br><span class="line">        <span class="built_in">this</span>.multiProducerConsumer = multiProducerConsumer;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">run</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                multiProducerConsumer.consume();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(rate);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MultiProducerConsumer</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 默认缓冲区的长度</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">DEFAULT_BUFFER_SIZE</span> <span class="operator">=</span> <span class="number">8</span>;</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> bufferSize;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 缓冲数组</span></span><br><span class="line">    <span class="type">char</span>[] bufferArray;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 生产者放置产品的位置、消费者获取产品的位置 (如果是 AtomicInteger， 生产者（消费者）自身就不需要互斥了)</span></span><br><span class="line">    <span class="type">int</span> putPos, pollPos;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 生产者使用缓冲的信号量、消费者消费产品的信号量</span></span><br><span class="line">    Semaphore bufferSemaphore, availableSemaphore;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 使用二级制信号量实现生产者、消费者各自的互斥锁，（Lock 或者其他锁形式也都是可以的）</span></span><br><span class="line">    Semaphore producerMutex, consumerMutex;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">MultiProducerConsumer</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>(DEFAULT_BUFFER_SIZE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">MultiProducerConsumer</span><span class="params">(<span class="type">int</span> bufferSize)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.bufferSize = bufferSize;</span><br><span class="line"></span><br><span class="line">        bufferArray = <span class="keyword">new</span> <span class="title class_">char</span>[bufferSize];</span><br><span class="line"></span><br><span class="line">        bufferSemaphore = <span class="keyword">new</span> <span class="title class_">Semaphore</span>(DEFAULT_BUFFER_SIZE);</span><br><span class="line">        availableSemaphore = <span class="keyword">new</span> <span class="title class_">Semaphore</span>(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">        producerMutex = <span class="keyword">new</span> <span class="title class_">Semaphore</span>(<span class="number">1</span>);</span><br><span class="line">        consumerMutex = <span class="keyword">new</span> <span class="title class_">Semaphore</span>(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 生产者生产产品</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">produce</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">        <span class="comment">// 若缓冲区已满，则阻塞</span></span><br><span class="line">        bufferSemaphore.acquire();</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> pos;</span><br><span class="line">        <span class="comment">// 原子地获取下一个放置的位置</span></span><br><span class="line">        producerMutex.acquire();</span><br><span class="line">        pos = putPos;</span><br><span class="line">        putPos = (putPos + <span class="number">1</span>) % bufferSize; <span class="comment">// 循环下移</span></span><br><span class="line">        <span class="comment">// 唤醒另一个因互斥而阻塞的生产者</span></span><br><span class="line">        producerMutex.release();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 执行生产操作 (可能耗时很大)</span></span><br><span class="line">        <span class="type">char</span> <span class="variable">c</span> <span class="operator">=</span> (<span class="type">char</span>) ((<span class="type">int</span>) <span class="string">&#x27;A&#x27;</span> + pos);</span><br><span class="line">        bufferArray[pos] = c;</span><br><span class="line">        System.out.printf(<span class="string">&quot;生产者 %s 放置产品 %c 到 buffer[%d]\n&quot;</span>, Thread.currentThread().getName(), c, pos);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 唤醒可能的消费者消费</span></span><br><span class="line">        availableSemaphore.release();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">consume</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">        <span class="comment">// 若缓冲区暂无产品消费，则阻塞</span></span><br><span class="line">        availableSemaphore.acquire();</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> pos;</span><br><span class="line">        <span class="comment">// 原子地获取下一个消费的位置</span></span><br><span class="line">        consumerMutex.acquire();</span><br><span class="line">        pos = pollPos;</span><br><span class="line">        pollPos = (pollPos + <span class="number">1</span>) % bufferSize; <span class="comment">// 循环下移</span></span><br><span class="line">        <span class="comment">// 唤醒另一个因互斥而阻塞的消费者</span></span><br><span class="line">        consumerMutex.release();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 执行消费操作 (可能耗时很大)</span></span><br><span class="line">        <span class="type">char</span> <span class="variable">c</span> <span class="operator">=</span> bufferArray[pos];</span><br><span class="line">        System.out.printf(<span class="string">&quot;消费者 %s 在 buffer[%d] 消费产品 %c\n&quot;</span>, Thread.currentThread().getName(), pos, c);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 唤醒可能的生产者继续生产</span></span><br><span class="line">        bufferSemaphore.release();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">        <span class="type">MultiProducerConsumer</span> <span class="variable">multiProducerConsumer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MultiProducerConsumer</span>();</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">1</span>; i &lt;= <span class="number">3</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">ProducerThread</span>(i,multiProducerConsumer).start();</span><br><span class="line">        &#125;</span><br><span class="line">        TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">1</span>; i &lt;= <span class="number">3</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">ConsumerThread</span>(i,multiProducerConsumer).start();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ul>
<h1 id="H2O生成"><a href="#H2O生成" class="headerlink" title="H2O生成"></a>H2O生成</h1><p><a target="_blank" rel="noopener" href="https://leetcode.cn/problems/building-h2o/">https://leetcode.cn/problems/building-h2o/</a></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Condition;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Lock;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">H2O</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="type">Lock</span> <span class="variable">lock</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReentrantLock</span>();</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> numOfO; <span class="comment">// O的生产缓冲队列</span></span><br><span class="line">    <span class="type">int</span> numOfH; <span class="comment">// H的生产缓冲队列</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 可以生产O的条件</span></span><br><span class="line">    <span class="type">Condition</span> <span class="variable">oCondition</span> <span class="operator">=</span> lock.newCondition();</span><br><span class="line">    <span class="comment">// 可以生产H的条件</span></span><br><span class="line">    <span class="type">Condition</span> <span class="variable">hCondition</span> <span class="operator">=</span> lock.newCondition();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">H2O</span><span class="params">()</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">ableGenerate</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> numOfO == <span class="number">1</span> &amp;&amp; numOfH == <span class="number">2</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">reset</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.numOfO = <span class="built_in">this</span>.numOfH = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">hydrogen</span><span class="params">(Runnable releaseHydrogen)</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">while</span> (numOfH == <span class="number">2</span>) &#123;</span><br><span class="line">                hCondition.await();</span><br><span class="line">            &#125;</span><br><span class="line">            numOfH++;</span><br><span class="line">            releaseHydrogen.run();</span><br><span class="line">            <span class="keyword">if</span> (ableGenerate()) &#123;</span><br><span class="line">                reset();</span><br><span class="line">                oCondition.signalAll();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">oxygen</span><span class="params">(Runnable releaseOxygen)</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">        lock.lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">while</span> (numOfO == <span class="number">1</span>) &#123;</span><br><span class="line">                oCondition.await();</span><br><span class="line">            &#125;</span><br><span class="line">            releaseOxygen.run();</span><br><span class="line">            numOfO++;</span><br><span class="line">            <span class="keyword">if</span> (ableGenerate()) &#123;</span><br><span class="line">                reset();</span><br><span class="line">                hCondition.signalAll();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2022/09/25/Java%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81%E8%BD%AC%E5%8C%96/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2022/09/25/Java%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81%E8%BD%AC%E5%8C%96/" class="post-title-link" itemprop="url">Java线程基本知识</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2022-09-25 17:00:01" itemprop="dateCreated datePublished" datetime="2022-09-25T17:00:01+08:00">2022-09-25</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-01-05 00:56:12" itemprop="dateModified" datetime="2023-01-05T00:56:12+08:00">2023-01-05</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Java%E5%A4%9A%E7%BA%BF%E7%A8%8B/" itemprop="url" rel="index"><span itemprop="name">Java多线程</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="多线程使用方式"><a href="#多线程使用方式" class="headerlink" title="多线程使用方式"></a>多线程使用方式</h1><h2 id="1-直接继承Thread"><a href="#1-直接继承Thread" class="headerlink" title="1. 直接继承Thread"></a>1. 直接继承Thread</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MyThread</span> <span class="keyword">extends</span> <span class="title class_">Thread</span> &#123;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">run</span><span class="params">()</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;here&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">MyThread</span> <span class="variable">myThread</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MyThread</span>();</span><br><span class="line">        myThread.start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="2-实现Runnable"><a href="#2-实现Runnable" class="headerlink" title="2. 实现Runnable"></a>2. 实现Runnable</h2><ol>
<li>传入Thread</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;here&quot;</span>);</span><br><span class="line">        &#125;).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<ol start="2">
<li>线程池池化</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.Executors;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        Executors.newCachedThreadPool().submit(<span class="keyword">new</span> <span class="title class_">Runnable</span>() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">run</span><span class="params">()</span> &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;here&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="comment">// or lambda</span></span><br><span class="line">        Executors.newCachedThreadPool().submit(() -&gt; System.out.println(<span class="string">&quot;here&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="3-使用Callable"><a href="#3-使用Callable" class="headerlink" title="3. 使用Callable"></a>3. 使用Callable</h2><ul>
<li>Callable接口类似于Runnable，需要<strong>实现接口中的call()方法</strong>。但是，Runnable不返回结果，也不能抛出已检查的异常。</li>
<li>Runnable接口提供run()方法支持用户定义线程的执行体，而Callable中提供call()方法。<ul>
<li><strong>拥有返回值</strong>。</li>
<li><strong>允许抛出异常</strong>。</li>
</ul>
</li>
<li>通过泛型我们可以知道，Callable接口中的形参类型需要和call方法返回值类型相同。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.Callable;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ExecutorService;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Executors;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Future;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">ExecutorService</span> <span class="variable">pool</span> <span class="operator">=</span> Executors.newCachedThreadPool();</span><br><span class="line">        Future&lt;String&gt; future = pool.submit(<span class="keyword">new</span> <span class="title class_">Callable</span>&lt;String&gt;() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> String <span class="title function_">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">                Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">                <span class="keyword">return</span> <span class="string">&quot;Hello&quot;</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// or lambda</span></span><br><span class="line"><span class="comment">//        pool.submit(() -&gt; &quot;Hello&quot;);</span></span><br><span class="line">        System.out.println(future.get());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="4-使用FutureTask"><a href="#4-使用FutureTask" class="headerlink" title="4. 使用FutureTask"></a>4. 使用FutureTask</h2><p>通过继承关系可以发现，<code>RunnableFuture</code>接口同时继承了<code>Runnable</code>和<code>Future</code>接口，意味着实现<code>RunnableFuture</code>接口的类既是Runnable的是实现类，又是Future的实现类。FutureTask就是充当这样的角色，<strong>它的实例可以作为target传入Thread的构造器中。</strong></p>
<p>通过查看源码，可以发现<strong>FutureTask内部维护了一个Callable的对象</strong>，可以通过下面的这个构造器初始化Callable对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        FutureTask&lt;String&gt; futureTask = <span class="keyword">new</span> <span class="title class_">FutureTask</span>&lt;&gt;(<span class="keyword">new</span> <span class="title class_">Callable</span>&lt;String&gt;() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> String <span class="title function_">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;here&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> <span class="string">&quot;hello&quot;</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="comment">// 1. Thread</span></span><br><span class="line">        <span class="keyword">new</span> <span class="title class_">Thread</span>(futureTask).start();</span><br><span class="line">        <span class="comment">// 2. pooled</span></span><br><span class="line">        Executors.newCachedThreadPool().submit(futureTask);</span><br><span class="line">        System.out.println(futureTask.get());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="5-使用CompletableFuture"><a href="#5-使用CompletableFuture" class="headerlink" title="5. 使用CompletableFuture"></a>5. 使用CompletableFuture</h2><p><a target="_blank" rel="noopener" href="https://juejin.cn/post/6844903594165026829">https://juejin.cn/post/6844903594165026829</a></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure>







<h1 id="状态变化"><a href="#状态变化" class="headerlink" title="状态变化"></a>状态变化</h1><p><code>java.lang.Thread.State</code>枚举类中定义了六种线程的状态，可以调用线程Thread中的<code>getState()</code>方法<strong>获取当前线程的状态</strong>。</p>
<table>
<thead>
<tr>
<th align="left">线程状态</th>
<th align="left">解释</th>
</tr>
</thead>
<tbody><tr>
<td align="left">NEW</td>
<td align="left">尚未启动的线程状态，即线程创建，<strong>还未调用start方法</strong></td>
</tr>
<tr>
<td align="left">RUNNABLE</td>
<td align="left"><strong>就绪状态</strong>（调用start，等待调度）+<strong>正在运行</strong></td>
</tr>
<tr>
<td align="left">BLOCKED</td>
<td align="left"><strong>等待监视器锁</strong>时，陷入阻塞状态</td>
</tr>
<tr>
<td align="left">WAITING</td>
<td align="left">等待状态的线程正在<strong>等待</strong>另一线程执行特定的操作（如notify）</td>
</tr>
<tr>
<td align="left">TIMED_WAITING</td>
<td align="left">具有<strong>指定等待时间</strong>的等待状态</td>
</tr>
<tr>
<td align="left">TERMINATED</td>
<td align="left">线程完成执行，<strong>终止状态</strong></td>
</tr>
</tbody></table>
<p><img src="/2022/09/25/Java%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81%E8%BD%AC%E5%8C%96/java-thread-state-transfer.png"></p>
<h2 id="一、新建状态-NEW"><a href="#一、新建状态-NEW" class="headerlink" title="一、新建状态(NEW)"></a>一、新建状态(NEW)</h2><p>即用<strong>new关键字</strong>新建一个线程，这个线程就处于<strong>新建状态</strong>。</p>
<h2 id="二、运行状态-RUNNABLE"><a href="#二、运行状态-RUNNABLE" class="headerlink" title="二、运行状态(RUNNABLE)"></a>二、运行状态(RUNNABLE)</h2><p>操作系统中的就绪和运行两种状态，在Java中统称为RUNNABLE。</p>
<h3 id="就绪状态（READY"><a href="#就绪状态（READY" class="headerlink" title="就绪状态（READY)"></a>就绪状态（READY)</h3><p>当线程对象调用了<code>start()</code>方法之后，线程处于<strong>就绪状态</strong>，就绪意味着该线程<strong>可以执行</strong>，但具体啥时候执行将取决于JVM里线程调度器的调度。</p>
<blockquote>
<p>It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.</p>
</blockquote>
<ul>
<li>不允许对一个线程多次使用start。</li>
<li>线程执行完成之后，不能试图用start将其唤醒。</li>
</ul>
<h4 id="其他状态-gt-就绪"><a href="#其他状态-gt-就绪" class="headerlink" title="其他状态 -&gt;就绪"></a>其他状态 -&gt;就绪</h4><ul>
<li>线程调用start()，新建状态转化为就绪状态。</li>
<li>线程sleep(long)时间到，等待状态转化为就绪状态。</li>
<li>阻塞式IO操作结果返回，线程变为就绪状态。</li>
<li>其他线程调用join()方法，结束之后转化为就绪状态。</li>
<li>线程对象拿到对象锁之后，也会进入就绪状态。</li>
</ul>
<h3 id="运行状态-RUNNING"><a href="#运行状态-RUNNING" class="headerlink" title="运行状态(RUNNING)"></a>运行状态(RUNNING)</h3><p>处于就绪状态的线程获得了CPU之后，<strong>真正开始执行run()方法的线程执行体时</strong>，意味着该线程就已经处于<strong>运行状态</strong>。需要注意的是，<strong>对于单处理器，一个时刻只能有一个线程处于运行状态。</strong><br>对于抢占式策略的系统来说，系统会给每个线程一小段时间处理各自的任务。时间用完之后，系统负责夺回线程占用的资源。下一段时间里，系统会根据一定规则，再次进行调度。</p>
<p><strong>运行状态转变为就绪状态</strong>的情形：</p>
<ul>
<li>线程失去处理器资源。线程不一定完整执行的，执行到一半，说不定就被别的线程抢走了。</li>
<li>调用yield()静态方法，暂时暂停当前线程，让系统的线程调度器重新调度一次，它自己完全有可能再次运行。</li>
</ul>
<p>yield方法的官方解释：</p>
<blockquote>
<p>A hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore this hint.</p>
</blockquote>
<p>提示调度程序，当前线程愿意放弃当前对处理器的使用。这时，<strong>当前线程将会被置为就绪状态</strong>，和其他线程一样等待调度，这时候根据不同<strong>优先级</strong>决定的<strong>概率</strong>，当前线程完全有可能再次抢到处理器资源。</p>
<h2 id="三、阻塞状态-BLOCKED"><a href="#三、阻塞状态-BLOCKED" class="headerlink" title="三、阻塞状态(BLOCKED)"></a>三、阻塞状态(BLOCKED)</h2><p>阻塞状态表示线程<strong>正等待监视器锁</strong>，而陷入的状态。</p>
<p>以下场景线程将会阻塞：</p>
<ul>
<li>线程等待进入synchronized同步方法。</li>
<li>线程等待进入synchronized同步代码块。</li>
</ul>
<p>线程取得锁，就会从阻塞状态转变为就绪状态。</p>
<h2 id="四、等待状态-WAITING"><a href="#四、等待状态-WAITING" class="headerlink" title="四、等待状态(WAITING)"></a>四、等待状态(WAITING)</h2><p>进入该状态表示<strong>当前线程需要等待其他线程做出一些的特定的动作</strong>（通知或中断）。</p>
<h3 id="运行-gt-等待"><a href="#运行-gt-等待" class="headerlink" title="运行-&gt;等待"></a>运行-&gt;等待</h3><ul>
<li>当前线程运行过程中，其他线程调用<code>join</code>方法，当前线程将会进入等待状态。</li>
<li>当前线程对象调用<code>wait()</code>方法。<br>-<code>LockSupport.park()</code>：出于线程调度的目的<strong>禁用当前线程</strong>。</li>
</ul>
<h3 id="等待-gt-就绪"><a href="#等待-gt-就绪" class="headerlink" title="等待-&gt;就绪"></a>等待-&gt;就绪</h3><ul>
<li>等待的线程<strong>被其他线程对象唤醒</strong>，<code>notify()</code>和<code>notifyAll()</code>。</li>
<li><code>LockSupport.unpark(Thread)</code>，与上面park方法对应，给出许可证，<strong>解除等待状态</strong>。</li>
</ul>
<h2 id="五、超时等待状态-TIMED-WAITING"><a href="#五、超时等待状态-TIMED-WAITING" class="headerlink" title="五、超时等待状态(TIMED_WAITING)"></a>五、超时等待状态(TIMED_WAITING)</h2><p>区别于<code>WAITING</code>，它可以在<strong>指定的时间</strong>自行返回。</p>
<h3 id="运行-gt-超时等待"><a href="#运行-gt-超时等待" class="headerlink" title="运行-&gt;超时等待"></a>运行-&gt;超时等待</h3><ul>
<li>调用静态方法，<code>Thread.sleep(long)</code></li>
<li>线程对象调用<code>wait(long)</code>方法</li>
<li>其他线程调用指定时间的<code>join(long)</code>。</li>
<li><code>LockSupport.parkNanos()</code>。</li>
<li><code>LockSupport.parkUntil()</code>。</li>
</ul>
<p>补充：<br>sleep和yield的不同之处：</p>
<ul>
<li>sleep(long)方法会<strong>使线程转入超时等待状态</strong>，时间到了之后才会转入就绪状态。而yield()方法不会将线程转入等待，而是强制线程进入就绪状态。</li>
<li>使用sleep(long)方法<strong>需要处理异常</strong>，而yield()不用。</li>
</ul>
<h3 id="超时等待-gt-就绪"><a href="#超时等待-gt-就绪" class="headerlink" title="超时等待-&gt;就绪"></a>超时等待-&gt;就绪</h3><ul>
<li>同样的，等待的线程被其他线程对象唤醒，<code>notify()</code>和<code>notifyAll()</code>。</li>
<li><code>LockSupport.unpark(Thread)</code>。</li>
</ul>
<h2 id="六、消亡状态"><a href="#六、消亡状态" class="headerlink" title="六、消亡状态"></a>六、消亡状态</h2><p>即<strong>线程的终止</strong>，表示线程已经执行完毕。前面已经说了，已经消亡的线程不能通过start再次唤醒。</p>
<ul>
<li>run()和call()线程执行体中顺利执行完毕，<strong>线程正常终止</strong>。</li>
<li>线程抛出一个没有捕获的Exception或Error。</li>
</ul>
<p>需要注意的是：主线成和子线程互不影响，子线程并不会因为主线程结束就结束。</p>
<blockquote>
<p>参考文章</p>
<p><a target="_blank" rel="noopener" href="https://www.cnblogs.com/summerday152/p/12288671.html">https://www.cnblogs.com/summerday152/p/12288671.html</a></p>
</blockquote>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2022/09/23/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E8%BF%9B%E7%A8%8B%E8%B0%83%E5%BA%A6%E7%AE%97%E6%B3%95/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2022/09/23/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E8%BF%9B%E7%A8%8B%E8%B0%83%E5%BA%A6%E7%AE%97%E6%B3%95/" class="post-title-link" itemprop="url">操作系统——进程与线程、调度算法</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>
      

      <time title="创建时间：2022-09-23 01:47:05 / 修改时间：15:57:05" itemprop="dateCreated datePublished" datetime="2022-09-23T01:47:05+08:00">2022-09-23</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" itemprop="url" rel="index"><span itemprop="name">操作系统</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h2 id="进程状态机"><a href="#进程状态机" class="headerlink" title="进程状态机"></a>进程状态机</h2><p><img src="/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E8%BF%9B%E7%A8%8B%E8%B0%83%E5%BA%A6%E7%AE%97%E6%B3%95/640.png" alt="图片"></p>
<ol>
<li>阻塞一般是当系统执行IO操作时，此时进程进入阻塞状态，等待某个事件的返回。</li>
<li>挂起是指进程没有占有物理内存，被写到磁盘上了。这时进程状态是挂起状态。</li>
</ol>
<blockquote>
<ol>
<li><code>阻塞挂起</code>：进程被写入硬盘并等待某个事件的出现。</li>
<li><code>就绪挂起</code>：进程被写入硬盘，进入内存可直接进入就绪状态。</li>
</ol>
</blockquote>
<h2 id="PCB——进程控制块"><a href="#PCB——进程控制块" class="headerlink" title="PCB——进程控制块"></a>PCB——进程控制块</h2><p>为了描述跟控制进程的运行，系统为每个进程定义了一个数据结构——<code>进程控制块 Process Control Block</code>，它是进程实体的一部分，是操作系统中最重要的记录型数据结构。</p>
<p>PCB 的作用是<strong>使一个在多道程序环境下不能独立运行的程序，成为一个能独立运行的基本单位，一个能与其它进程并发执行的进程</strong> :</p>
<ol>
<li>作为独立运行基本单位的标志；</li>
<li>实现间断性的运行方式；</li>
<li>提供进程管理所需要的信息；</li>
<li>提供进程调度所需要的信息；</li>
<li>实现与其他进程的同步与通信；</li>
</ol>
<h3 id="PCB-信息"><a href="#PCB-信息" class="headerlink" title="PCB 信息"></a>PCB 信息</h3><ol>
<li><strong>进程标识符</strong>：用于唯一地标识一个进程，一个进程通常有两种标识符：</li>
</ol>
<blockquote>
<ol>
<li><code>内部进程标识符</code>：标识各个进程，每个进程都有一个并且唯一的标识符，设置内部标识符主要是为了方便系统使用。</li>
<li><code>外部进程标识符</code>：它由创建者提供，可设置用户标识，以指示拥有该进程的用户。往往是由用户进程在访问该进程时使用。一般为了描述进程的家族关系，还应设置父进程标识及子进程标识。</li>
</ol>
</blockquote>
<ol start="2">
<li><strong>处理机状态</strong>：由各种寄存器组成。包含许多信息都放在寄存器中，方便程序restart。</li>
</ol>
<blockquote>
<ol>
<li>通用寄存器、指令计数器、程序状态字PSW、用户栈指针等信息。</li>
</ol>
</blockquote>
<ol start="3">
<li><strong>进程调度信息</strong></li>
</ol>
<blockquote>
<ol>
<li>进程状态：指明进程的当前状态，作为进程调度和对换时的依据。</li>
<li>进程优先级：用于描述进程使用处理机的优先级别的一个整数，优先级高的进程应优先获得处理机</li>
<li>进程调度所需的其它信息：与所采用的进程调度算法有关，如进程已等待CPU的时间总和、进程已执行的时间总和等。</li>
<li>事件：指进程由执行状态转变为阻塞状态所等待发生的事件，即阻塞原因。</li>
</ol>
</blockquote>
<ol start="4">
<li><strong>资源清单</strong></li>
</ol>
<blockquote>
<p>有关内存地址空间或虚拟地址空间的信息，所打开文件的列表和所使用的 I&#x2F;O 设备信息。</p>
</blockquote>
<h2 id="进程调度"><a href="#进程调度" class="headerlink" title="进程调度"></a>进程调度</h2><p><a target="_blank" rel="noopener" href="https://songyangji.gitee.io/2021/10/17/Linux%E8%BF%9B%E7%A8%8B%E8%B0%83%E5%BA%A6%E9%82%A3%E4%BA%9B%E4%BA%8B/">Linux进程调度那些事</a></p>
<h3 id="进程调度原则"><a href="#进程调度原则" class="headerlink" title="进程调度原则"></a>进程调度原则</h3><ol>
<li><strong>CPU 利用率</strong></li>
</ol>
<blockquote>
<ol>
<li>CPU利用率 &#x3D; 工作时间 &#x2F; 总时间。</li>
<li>调度程序应该尽量让 CPU 始终处于忙碌的状态，这可提高 CPU 的利用率。比如当发生IO读取时候，不要傻傻等待，去执行下别的进程。</li>
</ol>
</blockquote>
<ol start="2">
<li><strong>系统吞吐量</strong></li>
</ol>
<blockquote>
<ol>
<li>系统吞吐量 &#x3D; 总共完成多少个作业 &#x2F; 总共花费时间。</li>
<li>长作业的进程会占用较长的 CPU 资源导致降低吞吐量，相反短作业的进程会提升系统吞吐量。</li>
</ol>
</blockquote>
<ol start="3">
<li><strong>周转时间</strong></li>
</ol>
<blockquote>
<ol>
<li>周转时间 &#x3D; 作业完成时间 - 作业提交时间。</li>
<li>平均周转时间 &#x3D; 各作业周转时间和 &#x2F; 作业数</li>
<li>带权周转时间 &#x3D; 作业周转时间 &#x2F; 作业实际运行时间</li>
<li>平均带权周转时间 &#x3D; 各作业带权周转时间之和 &#x2F; 作业数</li>
<li>尽可能使周转时间降低。</li>
</ol>
</blockquote>
<ol start="4">
<li><strong>等待时间</strong></li>
</ol>
<blockquote>
<ol>
<li>指的是进程在等待队列中等待的时间，一般也需要尽可能短。</li>
</ol>
</blockquote>
<ol start="5">
<li><strong>响应时间</strong></li>
</ol>
<blockquote>
<p>响应时间 &#x3D; 系统第一次响应时间 - 用户提交时间，在交互式系统中响应时间是衡量调度算法好坏的主要标准。</p>
</blockquote>
<h3 id="调度算法"><a href="#调度算法" class="headerlink" title="调度算法"></a>调度算法</h3><p><em>FCFS 算法</em>*</p>
<ol>
<li>First Come First Severd 先来先服务算法，遵循先来后端原则，每次从就绪队列拿等待时间最久的，运行完毕后再拿下一个。</li>
<li>该模式对长作业有利，适用 CPU 繁忙型作业的系统，不适用 I&#x2F;O 型作业，因为会导致进程CPU利用率很低。</li>
</ol>
<p><strong>SJF 算法</strong></p>
<ol>
<li>Shortest Job First 最短作业优先算法，该算法会优先选择运行所需时间最短的进程执行，可提高吞吐量。</li>
<li>跟FCFS正好相反，对长作业很不利。</li>
</ol>
<blockquote>
<p>最短无法实际衡量，只能估计，很难实际应用。</p>
</blockquote>
<p><strong>RR 算法</strong></p>
<ol>
<li>Round Robin 时间片轮转算法，操作系统设定了个时间片Quantum，时间片导致每个进程只有在该时间片内才可以运行，这种方式导致每个进程都会均匀的获得执行权。</li>
<li>时间片一般20ms~50ms，如果太小会导致系统频繁进行上下文切换，太大又可能引起对短的交互请求的响应变差。</li>
</ol>
<h2 id="进程与线程的区别"><a href="#进程与线程的区别" class="headerlink" title="进程与线程的区别"></a>进程与线程的区别</h2><h3 id="线程定义"><a href="#线程定义" class="headerlink" title="线程定义"></a>线程定义</h3><blockquote>
<p>早期操作系统是没有线程概念的，线程是后来加进来的。为啥会有线程呢？那是因为以前在多进程阶段，经常会涉及到进程之间如何通讯，如何共享数据的问题。并且进程关联到PCB的生命周期，管理起来开销较大。为了解决这个问题引入了线程。</p>
</blockquote>
<p>线程是进程当中的一个执行流程。<strong>同一个进程内的多个线程之间可以共享进程的代码段、数据段、打开的文件等资源。</strong>同时<strong>每个线程又都有一套独立的寄存器和栈来确保线程的控制流是独立的</strong>。</p>
<p>在早期的操作系统中都是以<strong>进程作为独⽴运⾏的基本单位</strong>，直到后⾯，计算机科学家们⼜提出了更⼩的能独⽴运⾏的基本单位，也就是线程。</p>
<p><strong>线程与进程的⽐较如下</strong>：</p>
<p><strong>进程</strong>：</p>
<ol>
<li>是系统进行资源分配和调度的一个独立单位.</li>
<li>是程序的一次执行，每个进程都有自己的地址空间、内存、数据栈及其他辅助记录运行轨迹的数据</li>
</ol>
<p><strong>线程</strong>：</p>
<ol>
<li>是进程的一个实体，是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位</li>
<li>所有的线程运行在同一个进程中，共享相同的运行资源和环境</li>
<li>线程一般是并发执行的，使得实现了多任务的并行和数据共享。</li>
</ol>
<p><strong>进程线程区别</strong>：</p>
<ol>
<li>一个线程只能属于一个进程，而一个进程可以有多个线程，但至少有一个线程。</li>
<li>线程的划分尺度小于进程(资源比进程少)，使得多线程程序的并发性高。</li>
<li>进程在执行过程中拥有独立的内存单元，而多个线程共享内存，从而极大地提高了程序的运行效率。</li>
<li>资源分配给进程，同一进程的所有线程共享该进程的所有资源。</li>
<li>CPU分配资源给进程，但真正在CPU上运行的是线程。</li>
<li>线程不能够独立执行，必须依存在进程中。</li>
</ol>
<p><strong>Linux特性</strong>：</p>
<ol>
<li>Linux中没有真正的线程，因为Linux并没有为线程准备特定的数据结构。在内核看来只有进程而没有线程，在调度时也是当做进程来调度。Linux所谓的线程其实是与其他进程共享资源的进程。但windows中确实有线程。</li>
<li>Linux中没有的线程，线程是由进程来模拟实现的。</li>
<li>所以在Linux中在CPU角度看，进程被称作轻量级进程LWP。</li>
</ol>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2022/09/23/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E9%A1%B5%E9%9D%A2%E7%BD%AE%E6%8D%A2%E7%AE%97%E6%B3%95/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2022/09/23/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E2%80%94%E2%80%94%E9%A1%B5%E9%9D%A2%E7%BD%AE%E6%8D%A2%E7%AE%97%E6%B3%95/" class="post-title-link" itemprop="url">操作系统——页面置换算法</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2022-09-23 01:46:02" itemprop="dateCreated datePublished" datetime="2022-09-23T01:46:02+08:00">2022-09-23</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2022-10-27 08:30:29" itemprop="dateModified" datetime="2022-10-27T08:30:29+08:00">2022-10-27</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" itemprop="url" rel="index"><span itemprop="name">操作系统</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h2 id="缺页中断"><a href="#缺页中断" class="headerlink" title="缺页中断"></a>缺页中断</h2><p>当 CPU 访问的⻚⾯不在物理内存时，便会产⽣⼀个缺⻚中断，请求操作系统将所缺⻚调⼊到物理内存。那它与⼀般中断的主要区别在于：<br>缺⻚中断在指令执⾏「期间」产⽣和处理中断信号，⽽⼀般中断在⼀条指令执⾏「完成」后检查和处理中断信号。</p>
<p>缺⻚中断返回到该指令的开始重新执⾏「该指令」，⽽⼀般中断返回回到该指令的「下⼀个指令」执⾏。</p>
<ol>
<li>在 CPU ⾥访问⼀条 Load M 指令，然后 CPU 会去找 M 所对应的⻚表项。</li>
<li>如果该⻚表项的状态位是「有效的」，那 CPU 就可以直接去访问物理内存了，如果状态位是「⽆效的」，则 CPU 则会发送缺⻚中断请求。</li>
<li>操作系统收到了缺⻚中断，则会执⾏缺⻚中断处理函数，先会查找该⻚⾯在磁盘中的⻚⾯的位置。</li>
<li>找到磁盘中对应的⻚⾯后，需要把该⻚⾯换⼊到物理内存中，<strong>但是在换⼊前，需要在物理内存中找空闲⻚</strong>，如果找到空闲⻚，就把⻚⾯换⼊到物理内存中。</li>
<li>⻚⾯从磁盘换⼊到物理内存完成后，则把⻚表项中的状态位修改为「有效的」。</li>
<li>最后，CPU 重新执⾏导致缺⻚异常的指令。</li>
</ol>
<p>上⾯所说的过程，第 4 步是能在物理内存找到空闲⻚的情况，那如果找不到呢？</p>
<p>找不到空闲⻚的话，就说明此时内存已满了，这时候，就需要「⻚⾯置换算法」选择⼀个物理⻚，如果该</p>
<p>物理⻚有被修改过（脏⻚），则把它换出到磁盘，然后把该被置换出去的⻚表项的状态改成「⽆效的」，</p>
<p>最后把正在访问的⻚⾯装⼊到这个物理⻚中。</p>
<p>所以，<strong>⻚⾯置换算法的功能</strong>是，<strong>当出现缺⻚异常，需调⼊新⻚⾯⽽内存已满时，选择被置换的物理⻚⾯，</strong></p>
<p><strong>也就是说选择⼀个物理⻚⾯换出到磁盘，然后把需要访问的⻚⾯换⼊到物理⻚。</strong></p>
<p>那其算法⽬标则是，<strong>尽可能减少⻚⾯的换⼊换出的次数</strong>，常⻅的⻚⾯置换算法有如下⼏种：</p>
<p>常⻅的⻚⾯置换算法有如下⼏种：</p>
<ol>
<li><p>最佳⻚⾯置换算法（<em>OPT</em>）</p>
</li>
<li><p>先进先出置换算法（<em>FIFO</em>）最近最久未使⽤的置换算法（<em>LRU</em>）</p>
</li>
<li><p>时钟⻚⾯置换算法（<em>Lock</em>）</p>
</li>
<li><p>最不常⽤置换算法（<em>LFU</em>）</p>
</li>
</ol>
<h3 id="最佳⻚⾯置换算法OPT"><a href="#最佳⻚⾯置换算法OPT" class="headerlink" title="最佳⻚⾯置换算法OPT"></a>最佳⻚⾯置换算法OPT</h3><p>最佳⻚⾯置换算法基本思路是，<strong>置换在「未来」最⻓时间不访问的⻚⾯</strong>。</p>
<p>这很理想，但是实际系统中⽆法实现，因为程序访问⻚⾯时是动态的，我们是⽆法预知每个⻚⾯在「下⼀次」访问前的等待时间。</p>
<p>所以，最佳⻚⾯置换算法作⽤是为了衡量你的算法的效率，你的算法效率越接近该算法的效率，那么说明你的算法是⾼效的。</p>
<h3 id="先进先出置换算法FIFO"><a href="#先进先出置换算法FIFO" class="headerlink" title="先进先出置换算法FIFO"></a>先进先出置换算法FIFO</h3><p>既然我们⽆法预知⻚⾯在下⼀次访问前所需的等待时间，那我们可以<strong>选择在内存驻留时间很⻓的⻚⾯进⾏中置换</strong>，这个就是「先进先出置换」算法的思想。</p>
<h3 id="最近最少使⽤的置换算法LRU"><a href="#最近最少使⽤的置换算法LRU" class="headerlink" title="最近最少使⽤的置换算法LRU"></a>最近最少使⽤的置换算法LRU</h3><p>最近最少使⽤（<em>LRU</em>）的置换算法的基本思路是，发⽣缺⻚时，选择最⻓时间没有被访问的⻚⾯进⾏置换，也就是说，<strong>该算法假设已经很久没有使⽤的⻚⾯很有可能在未来较⻓的⼀段时间内仍然不会被使⽤</strong>。</p>
<p>这种算法近似最优置换算法，最优置换算法是通过「未来」的使⽤情况来推测要淘汰的⻚⾯，⽽ LRU 则是通过「历史」的使⽤情况来推测要淘汰的⻚⾯。</p>
<p>虽然 LRU 在理论上是可以实现的，但代价很⾼。为了完全实现 LRU，需要在内存中维护⼀个所有⻚⾯的链表，最近最多使⽤的⻚⾯在表头，最近最少使⽤的⻚⾯在表尾。<br>困难的是，在每次访问内存时都必须要更新「整个链表」。在链表中找到⼀个⻚⾯，删除它，然后把它移动到表头是⼀个⾮常费时的操作。</p>
<blockquote>
<p>所以，LRU 虽然看上去不错，但是由于开销⽐较⼤，实际应⽤中⽐较少使⽤。</p>
</blockquote>
<h3 id="时钟⻚⾯置换算法——Clock算法"><a href="#时钟⻚⾯置换算法——Clock算法" class="headerlink" title="时钟⻚⾯置换算法——Clock算法"></a>时钟⻚⾯置换算法——Clock算法</h3><p>简单的CLOCK算法是给每一帧关联一个附加位，称为使用位。</p>
<p>当某一页首次装入主存时，该帧的使用位设置为1;当该页随后再被访问到时，它的使用位也被置为1。</p>
<p>对于页替换算法，用于替换的候选帧集合看做一个循环缓冲区，并且有一个指针与之相关联。</p>
<p>当某一页被替换时，该指针被设置成指向缓冲区中的下一帧。当需要替换一页时，操作系统扫描缓冲区，以查找使用位被置为0的一帧。</p>
<p><strong>每当遇到一个使用位为1的帧时，操作系统就将该位重新置为0；如果在这个过程开始时，缓冲区中所有帧的使用位均为0，则选择遇到的第一个帧替换</strong>；如果所有帧的使用位均为1,则指针在缓冲区中完整地循环一周，把所有使用位都置为0，并且停留在最初的位置上，替换该帧中的页。</p>
<p>由于该算法循环地检查各页面的情况，故称为CLOCK算法，又称为最近未用(Not Recently Used, NRU)算法。</p>
<h3 id="改进型的-clock-算法"><a href="#改进型的-clock-算法" class="headerlink" title="改进型的 clock 算法"></a>改进型的 clock 算法</h3><p>CLOCK算法的性能比较接近LRU，而通过增加使用的位数目，可以使得CLOCK算法更加高效。在使用位的基础上再增加一个修改位，则得到改进型的CLOCK置换算法。</p>
<p>这样，每一帧都处于以下四种情况之一：</p>
<ol>
<li>最近未被访问，也未被修改(u&#x3D;0, m&#x3D;0)。</li>
<li>最近被访问，但未被修改(u&#x3D;1, m&#x3D;0)。</li>
<li>最近未被访问，但被修改(u&#x3D;0, m&#x3D;1)。</li>
<li>最近被访问，被修改(u&#x3D;1, m&#x3D;1)。</li>
</ol>
<p>改进型的CLOCK算法优于简单CLOCK算法之处在于替换时首选没有变化的页。<strong>由于修改过的页在被替换之前必须写回</strong>，因而这样做会节省时间。</p>
<h3 id="最不常⽤页面置换算法"><a href="#最不常⽤页面置换算法" class="headerlink" title="最不常⽤页面置换算法"></a>最不常⽤页面置换算法</h3><p>当发⽣缺⻚中断时，选择「访问次数」最少的那个⻚⾯，并将其淘汰。<br>它的实现⽅式是，对每个⻚⾯设置⼀个「访问计数器」，每当⼀个⻚⾯被访问时，该⻚⾯的访问计数器就累加 1。在发⽣缺⻚中断时，淘汰计数器值最⼩的那个⻚⾯。</p>
<h1 id="页面抖动-颠簸-和工作集-驻留集"><a href="#页面抖动-颠簸-和工作集-驻留集" class="headerlink" title="页面抖动(颠簸)和工作集(驻留集)"></a>页面抖动(颠簸)和工作集(驻留集)</h1><h2 id="页面抖动（颠簸）"><a href="#页面抖动（颠簸）" class="headerlink" title="页面抖动（颠簸）"></a>页面抖动（颠簸）</h2><p>在页面置换过程中的一种最糟糕的情形是，刚刚换出的页面马上又要换入主存，刚刚换入的页面马上就要换出主存，这种频繁的页面调度行为称为抖动，或颠簸。</p>
<p>如果一个进程在换页上用的时间多于执行时间，那么这个进程就在颠簸。</p>
<p>频繁的发生缺页中断（抖动），其主要原因是某个进程频繁访问的页面数目高于可用的物理页帧数目。</p>
<p>虚拟内存技术可以在内存中保留更多的进程以提髙系统效率。在稳定状态，几乎主存的所有空间都被进程块占据，处理机和操作系统可以直接访问到尽可能多的进程。</p>
<p>但如果管理不当，处理机的大部分时间都将用于交换块，即请求调入页面的操作，而不是执行进程的指令，这就会大大降低系统效率。</p>
<h2 id="工作集（驻留集）"><a href="#工作集（驻留集）" class="headerlink" title="工作集（驻留集）"></a>工作集（驻留集）</h2><p>工作集（或驻留集）是指在某段时间间隔内，进程要访问的页面集合。</p>
<p>经常被使用的页面需要在工作集中，而长期不被使用的页面要从工作集中被丢弃。为了防止系统出现抖动现象，需要选择合适的工作集大小。</p>
<p>工作集模型的原理是：让操作系统跟踪每个进程的工作集，并为进程分配大于其工作集的物理块。</p>
<p>如果还有空闲物理块，则可以再调一个进程到内存以增加多道程序数。如果所有工作集之和增加以至于超过了可用物理块的总数，那么操作系统会暂停一个进程，将其页面调出并且将其物理块分配给其他进程，防止出现抖动现象。</p>
<p>正确选择工作集的大小，对存储器的利用率和系统吞吐量的提嵩，都将产生重要影响。</p>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




  <nav class="pagination">
    <a class="extend prev" rel="prev" title="上一页" aria-label="上一页" href="/page/6/"><i class="fa fa-angle-left"></i></a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/6/">6</a><span class="page-number current">7</span><a class="page-number" href="/page/8/">8</a><span class="space">&hellip;</span><a class="page-number" href="/page/26/">26</a><a class="extend next" rel="next" title="下一页" aria-label="下一页" href="/page/8/"><i class="fa fa-angle-right"></i></a>
  </nav>

</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">SongyangJi</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/muse/" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>
  <div class="sidebar-dimmer"></div>
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/schemes/muse.js"></script><script src="/js/next-boot.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>





  





</body>
</html>
